package 设计模式.创建型.工厂模式.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import 设计模式.创建型.工厂模式.sc.ScheduleClass;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 抽象的排课策略工厂
 * @author lchenglong
 * @date 2024/1/26
 */
//@Component
public abstract class ScheduleClassFactory<T, S extends ScheduleClass<T>>
        implements InitializingBean, ApplicationContextAware {

    private Map<T, S> scheduleClassMap;

    private ApplicationContext appContext;

    /**
     * 根据策略 id 获得对应的策略的 Bean
     *
     * @param id 策略 id
     * @return 策略的 Bean
     */
    public S getHandler(T id) {
        return scheduleClassMap.get(id);
    }
    /**
     * 通过反射获取策略的类型
     *
     * @return 策略的类型
     */
    protected abstract Class<S> getScheduleClassType() ;
//    {
//        // getClass 获取当前运行时实例的类，getGenericSuperclass 获得泛型父类
//        Type superclass = getClass().getGenericSuperclass();
//        ParameterizedType pt = (ParameterizedType) superclass;
//        Type[] actualTypeArguments = pt.getActualTypeArguments();
//        // 获得索引为 1 的实际参数类型，即第二个实际参数的类型
//        Type actualTypeArgument = actualTypeArguments[1];
//        @SuppressWarnings("unchecked")
//        Class<S> result = (Class<S>) actualTypeArgument;
//
//        return result;
//    }

    @Override
    public void afterPropertiesSet() {
        // 获取 Spring 容器中，所有 S 类型的 Bean
        Collection<S> scheduleClassList = appContext.getBeansOfType(getScheduleClassType()).values();

        scheduleClassMap = new HashMap<>(scheduleClassList.size());

        // 将所有 S 类型的 Bean 放入到 strategyMap 中
        for (final S scheduleClass : scheduleClassList) {
            T id = scheduleClass.getId();
            scheduleClassMap.put(id, scheduleClass);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;
    }

}
